﻿using System;
using System.Collections.Generic;
using UnityEngine;
using Yoozoo.Framework.Core;
using Yoozoo.Libs;
using Yoozoo.Managers;
using Random = UnityEngine.Random;

namespace Gameplay.PVE.Survivor
{
    public class BattlePropsManager: BattleSingleton<BattlePropsManager>
    {
        //todo 后续改成格子，减少遍历次数
        private List<BattlePropsData> propsList = new List<BattlePropsData>();
        private Dictionary<int,Dictionary<int,Vector3>> dropMap = new   Dictionary<int, Dictionary<int,Vector3>>();
        private class BattlePropsData : IClass
        {
            public BattleGameObject battleGameObject;
            public BattleGameObject effect;
            public EBattlePropsType type;
            public List<int> param;
            public Vector3 position;
            public float radius;
            public int value;
            public int resId;
            public int flyTextResId = 0;
            public string flyText = String.Empty;
            private float startTime;
            private float maxHeight;
            private float acceleration = SurvivorManager.dropGravity;
            private float startHeight;
            private Vector3 endPosition;

            private float timeUp;
            private float timeDown;

            private Vector3 horizontalSpeed;

            private bool parabolaFinished = false;

            private bool isPicking = false;

            public bool needDispose = false;
            
            private float pickStartTime;
            private float pickFlyTime = 0.5f;
            private Vector3 pickStartPosition;

            public void InitParabola(Vector3 startPosition, Vector3 direction, float flyTime, float speed,
                int resid = (int)EBattleResId.DropDollar)
            {
                needDispose = false;
                parabolaFinished = false;
                isPicking = false;
                startHeight = startPosition.y;
                timeDown = startHeight / acceleration / flyTime + flyTime / 2;
                timeUp = flyTime - timeDown;
                maxHeight = 0.5f * acceleration * timeUp * timeUp + startHeight;
                startTime = TimeManager.gameTime;
                horizontalSpeed = direction.normalized * speed;
                startPosition.y = 0;
                position = startPosition;
                endPosition = startPosition + direction * speed * flyTime;
                endPosition.y = BattleEffectManager.GetGroundHeight(endPosition);
                timeDown = Mathf.Sqrt(2 * (maxHeight - endPosition.y) / acceleration);
                this.resId = resid;
            }
            
            public void Create()
            {
                battleGameObject = BattlePoolManager.Instance.Get(resId);
                battleGameObject.Position = position;
            }

            public void CheckCollision(Vector3 position)
            {
                if (!CanPick())
                {
                    return;
                }

                if (BattlePropsManager.Instance.isAutoPick)
                {
                    StartPick();
                    return;
                }
                var xDiff = position.x - endPosition.x;
                var zDiff = position.z - endPosition.z;
                if (xDiff * xDiff + zDiff * zDiff < radius * radius)
                {
                    StartPick();
                }
            }

            public void StartPick()
            {
                pickStartTime = TimeManager.gameTime;
                isPicking = true;
                pickStartPosition = battleGameObject.Position;
                if (effect != null)
                {
                    BattlePoolManager.Instance.Release(effect);
                    effect = null;
                }
            }
            
            public bool IsPicking()
            {
                return isPicking;
            }
            
            private void UpdatePicking()
            {
                var targetPosition = StageManager.Instance.TeamGroup.Position + new Vector3(0,1,0);
                var time = TimeManager.gameTime - pickStartTime;
                var percent = time / pickFlyTime;
                if (percent >= 1)
                {
                    percent = 1;
                    switch (type)
                    {
                        case EBattlePropsType.Dollar:
                            SurvivorDataManager.Instance.AddDollar(value);
                            break;
                        case EBattlePropsType.Buffs:
                            SurvivorDataManager.Instance.AddBuffsToTeam(param);
                            break;
                    }
                    needDispose = true;
                    if (flyTextResId != 0)
                    {
                        FlyTextManager.Instance.ShowFlyTextByResID(flyTextResId,targetPosition,flyText);
                    }
                }
                percent = percent * percent;
                battleGameObject.Position = Vector3.Lerp(pickStartPosition,targetPosition,percent);
            }
            
            public void Update()
            {
                if (isPicking)
                {
                    UpdatePicking();
                    return;
                }
                if (parabolaFinished)
                {
                    return;
                }
                var time = TimeManager.gameTime - startTime;
                var h = 0f;
                if (time < timeUp)
                {
                    var restTime = timeUp - time;
                    h = maxHeight - 0.5f * acceleration * restTime * restTime;
                }
                else if (time < timeUp + timeDown)
                {
                    var fallTime = time - timeUp;
                    h = maxHeight - 0.5f * acceleration * fallTime * fallTime;
                    if (endPosition.y >= h)
                    {
                        parabolaFinished = true;
                        h = endPosition.y;
                    }
                }
                else
                {
                    parabolaFinished = true;
                    h = endPosition.y;
                }
                battleGameObject.Position = new Vector3(position.x,h,position.z) + horizontalSpeed * time;
                if (parabolaFinished)
                {
                    endPosition = battleGameObject.Position;
                    if (type == EBattlePropsType.Buffs)
                    {
                        CreatEffect();
                    }
                }
            }
            
            public void CreatEffect()
            {
                effect = BattlePoolManager.Instance.Get(5023);
                effect.Position = endPosition;
            }
            
            public void OnReset()
            {
                if (battleGameObject != null)
                {
                    BattlePoolManager.Instance.Release(battleGameObject);
                    battleGameObject = null;
                }

                if (effect != null)
                {
                    BattlePoolManager.Instance.Release(effect);
                    effect = null;
                }

                flyTextResId = 0;
                flyText = String.Empty;
                isPicking = false;
                needDispose = false;
            }

            public bool CanPick()
            {
                return parabolaFinished && !isPicking;
            }
        }

        public void SetAutoPick(bool value)
        {
            isAutoPick = value;
        }
        
        private bool isAutoPick = false;

        private float dollarRatio;

        public void SetDollarRatio(float ratio)
        {
            dollarRatio = ratio;
        }
        
        private static List<int> dropSingleUnit = new List<int> {50,100,200,300};
        public  void Initialize(int missionID)
        {
            var config = BattleConfigManager.Instance.GetRpgMissionConfig(missionID);
            if (config==null)
            {
                return;
            }
            dropMap.Clear();
            foreach (var item in config.drop_item)
            {
                Dictionary<int, Vector3> subdic = null;
                if (!dropMap.TryGetValue((int)item.x, out subdic))
                {
                    subdic = new Dictionary<int, Vector3>();
                    dropMap.Add((int)item.x, subdic);
                }

                if (!subdic.ContainsKey((int)item.y))
                {
                    subdic.Add((int)item.y, item);
                }
                else
                {
                    if (BattleDebug.enableLog)
                    {
                        BattleDebug.Log("error dorp_item id MissingID:" + missionID + "  UintID:" + item.x + "  itemID:" +
                                        item.y);
                    }
                }
            }
        }

        public void CheckoutUnitDrop(int configID,Vector3 position,Vector3 forward)
        {
            Dictionary<int, Vector3> subCfg;
            if (!dropMap.TryGetValue(configID, out subCfg))
            {
                if (!dropMap.TryGetValue(-1, out subCfg))
                {
                    return;
                }
            }

            foreach (var item in subCfg.Values)
            {
                var radom = Random.Range(0,10000);
                var curPro = item.z;
                if (radom < curPro)
                {
                    DropItemInternal((int)item.y,position,forward);
                }
            }
        }

        private void DropItemInternal(int id,Vector3 position,Vector3 forward)
        {
            var config = BattleConfigManager.Instance.GetBattleDropItemConfig(id);
            if (config == null)
            {
                return;
            }
            var propsData = ClassManager.Get<BattlePropsData>();
            propsData.type = EBattlePropsType.Buffs;
            propsData.param = config.param;
            if (config.name != String.Empty)
            {
                var text = BattleConfigManager.GetLangText(config.name);
                propsData.flyText = text;
                propsData.flyTextResId = 207;
            }
            propsData.position = position;
            propsData.radius = 2f;
            var speed = Random.Range(2.5f,4f);
            propsData.InitParabola(position + new Vector3(0,SurvivorManager.dropStartHeight,0),forward,SurvivorManager.dropFlyTime,speed,config.res_id);
            propsData.Create();
            propsList.Add(propsData);
        }

        public void CreateDropDollar(Vector3 position,Vector3 forward,int dollarCount)
        {
            var totalDollar = dollarCount * dollarRatio;
            var singleUnit = dropSingleUnit[Random.Range(0,dropSingleUnit.Count)];
            var count = Mathf.CeilToInt(totalDollar / singleUnit);
            count = Mathf.Min(count, 20);
            singleUnit = Mathf.CeilToInt(totalDollar / count);
            for (int i = 0; i < count; i++)
            {
                var direction = Quaternion.AngleAxis(Random.Range(-90,90),Vector3.up) * forward;
                var speed = Random.Range(2.5f,4f);
                var currentDrop = singleUnit;
                if (totalDollar < singleUnit)
                {
                    currentDrop = (int)totalDollar;
                }
                totalDollar -= singleUnit;
                DropDollarInternal(position,direction,(int)currentDrop,speed);
            }
        }

        private void DropDollarInternal(Vector3 position, Vector3 forward, int dollarCount,float speed)
        {
            var propsData = ClassManager.Get<BattlePropsData>();
            propsData.type = EBattlePropsType.Dollar;
            propsData.position = position;
            propsData.value = dollarCount;
            propsData.radius = 8f;
            propsData.InitParabola(position + new Vector3(0,SurvivorManager.dropStartHeight,0),forward,SurvivorManager.dropFlyTime,speed);
            propsData.Create();
            propsList.Add(propsData);
        }

        public override void Update()
        {
            var checkCollision = false;
            Vector3 checkPosition = Vector3.zero;
            if (StageManager.Instance.TeamGroup != null)
            {
                checkCollision = true;
                checkPosition = StageManager.Instance.TeamGroup.Position;
            }
            for (int i = 0; i < propsList.Count; i++)
            {
                var propsData = propsList[i];
                propsData.Update();
                if (checkCollision)
                {
                    propsData.CheckCollision(checkPosition);
                }
                if (propsData.needDispose)
                {
                    if (i < propsList.Count)
                    {
                        propsList[i] = propsList[propsList.Count - 1];
                        ClassManager.Free(propsData);
                    }
                    propsList.RemoveAt(propsList.Count - 1);
                    i--;
                }
            }
        }

        public void PickAllProps()
        {
            for (int i = 0; i < propsList.Count; i++)
            {
                var propsData = propsList[i];
                if (!propsData.IsPicking())
                {
                    propsData.StartPick();
                }
            }
        }

        public override void Dispose()
        {
            for (int i = 0; i < propsList.Count; i++)
            {
                ClassManager.Free(propsList[i]);
            }
            propsList.Clear();
        }
    }
}
